package org.jsola.hr.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.jsola.admin.constant.AsyncTaskTypeEnum;
import org.jsola.admin.constant.TaskStatusEnum;
import org.jsola.admin.constant.TaskSubjectResultEnum;
import org.jsola.admin.entity.AsyncTaskDO;
import org.jsola.admin.entity.AsyncTaskDetailDO;
import org.jsola.admin.entity.SiteDO;
import org.jsola.admin.service.IAsyncTaskDetailService;
import org.jsola.admin.service.IAsyncTaskService;
import org.jsola.common.*;
import org.jsola.admin.vo.SiteVO;
import org.jsola.common.ClassKit;
import org.jsola.common.PageKit;
import org.jsola.common.SafeKit;
import org.jsola.common.StrKit;
import org.jsola.core.Page;
import org.jsola.core.entity.BaseCreateDO;
import org.jsola.core.entity.BaseDO;
import org.jsola.exception.ParamException;
import org.jsola.hr.common.BeanCopyUtil;
import org.jsola.hr.common.CacheKeyKit;
import org.jsola.hr.common.EmpFieldModuleCodeKit;
import org.jsola.hr.common.ExampleKit;
import org.jsola.hr.constant.CustomerModuleType;
import org.jsola.hr.constant.HrConstants;
import org.jsola.hr.dao.ICustomTemplateDAO;
import org.jsola.hr.dto.*;
import org.jsola.hr.entity.*;
import org.jsola.hr.exception.HrException;
import org.jsola.hr.provider.IAdminProviderService;
import org.jsola.hr.query.CompanyNecessaryFieldQuery;
import org.jsola.hr.query.CustomTemplateFieldQuery;
import org.jsola.hr.query.CustomTemplateQuery;
import org.jsola.hr.service.*;
import org.jsola.hr.vo.*;
import org.jsola.user.core.TokenUser;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import static org.jsola.hr.constant.HrConstants.JIA_FANG_QY;
import static org.jsola.hr.constant.HrConstants.JIA_FANG_SY;

/**
 * 自定义模板
 *
 * @author zhr
 */
@Slf4j
@Service("hrCustomTemplateServiceImpl")
public class CustomTemplateServiceImpl implements ICustomTemplateService {

    @Autowired
    private ICustomTemplateDAO customTemplateDAO;

    @Autowired
    private ICustomTemplateFieldService customTemplateFieldService;

    @Autowired
    private ICheckInPeopleService checkInPeopleService;

    @Autowired
    private ICompanyService companyService;

    @Autowired
    private ICompanyAdditionalFieldsService companyAdditionalFieldsService;

    @Autowired
    private IEmpAdditionalFieldsService empAdditionalFieldsService;

    @Autowired
    private IEmpInfoService empInfoService;

    @Autowired
    private ISocProgService socProgService;

    @Autowired
    private IEmpFamilyService familyService;

    @Autowired
    private IEmpContactsService contactsService;

    @Autowired
    private IAdminProviderService adminProviderService;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private IAsyncTaskService asyncTaskService;

    @Autowired
    private IAsyncTaskDetailService asyncTaskDetailService;

    @Autowired
    private ICompanyNecessaryFieldService companyNecessaryFieldService;

    @Autowired
    private IEmpEducationService empEducationService;

    @Autowired
    private IEmpWorkService empWorkService;

    @Autowired
    private IEmpTrainService empTrainService;

    @Autowired
    private IEmpRewardPunishService empRewardPunishService;

    /**
     * 系统
     */
    private final static Integer TYPE_SYSTEM = 1;
    /**
     * 租户
     */
    private final static Integer TYPE_SITE = 2;
    /**
     * 用工单位
     */
    private final static Integer TYPE_COMPANY = 3;
    /**
     * 默认模板
     */
    private final static String DEFAULT_TEMPLATE_NAME = "默认模板";

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public CustomTemplateVO save(CustomTemplateAddDTO customTemplateAddDTO, TokenUser tokenUser) {
        // 转DO
        CustomTemplateDO customTemplateDO = customTemplateAddDTO.to(CustomTemplateDO.class);
        // 保存
        customTemplateDO = save(customTemplateDO, tokenUser.getSiteId(), tokenUser.getUserId());
        return customTemplateDO.to(CustomTemplateVO.class);
    }

    @Override
    public int saveDefaultBySite(TokenUser tokenUser) {
        // 系统级默认模板
        List<CustomTemplateDO> defaultDOList = selectBySystem(null, null);
        // 租户级默认模板
        List<CustomTemplateDO> siteDOList = selectDefaultBySite(tokenUser.getSiteId());
        List<String> moduleCodes = siteDOList.parallelStream()
                .map(CustomTemplateDO::getModuleCode).collect(Collectors.toList());
        for (CustomTemplateDO customTemplateDO : defaultDOList) {
            // 若租户不存在 则需要新建
            if (!moduleCodes.contains(customTemplateDO.getModuleCode())) {
                CustomTemplateAddDTO customTemplateAddDTO = customTemplateDO.to(CustomTemplateAddDTO.class);
                customTemplateAddDTO.setCompanyId(HrConstants.ADD_FIELD_COMPANY_SITE);
                // 查询是否有开启的模板，没有设为开启
                List<CustomTemplateDO> customTemplateDOS =
                        selectOpen(HrConstants.ADD_FIELD_COMPANY_SITE, customTemplateAddDTO.getModuleCode(), tokenUser);
                customTemplateAddDTO.setIsOpen(CollectionUtils.isEmpty(customTemplateDOS));
                customTemplateAddDTO.setType(2);
                CustomTemplateVO save = save(customTemplateAddDTO, tokenUser);
                // 默认模板下的字段
                TokenUser defaultTokenUser = new TokenUser(tokenUser.getUserId(), HrConstants.DEFAULT);
                List<CustomTemplateFieldVO> customTemplateFieldVOList = customTemplateFieldService
                        .listByTemplateId(customTemplateDO.getId(), defaultTokenUser);
                List<CustomTemplateFieldAddDTO> customTemplateFieldAddDTOList = new ArrayList<>();
                for (CustomTemplateFieldVO customTemplateFieldVO : customTemplateFieldVOList) {
                    CustomTemplateFieldAddDTO customTemplateFieldAddDTO = customTemplateFieldVO.to(CustomTemplateFieldAddDTO.class);
                    customTemplateFieldAddDTO.setCompanyId(HrConstants.ADD_FIELD_COMPANY_SITE);
                    customTemplateFieldAddDTO.setTemplateId(save.getId());
                    customTemplateFieldAddDTOList.add(customTemplateFieldAddDTO);
                }
                customTemplateFieldService.batchSave(customTemplateFieldAddDTOList, tokenUser);
            }
        }
        return defaultDOList.size();
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int update(CustomTemplateUpdateDTO customTemplateUpdateDTO, TokenUser tokenUser) {
        // 系统字段
        List<CustomTemplateFieldAddDTO> fieldAddDTOList = customTemplateUpdateDTO.getCustomFieldAddDTOList();
        // 自定义字段
        List<CompanyAdditionalFieldsAddDTO> additionalFieldsAddDTOList = customTemplateUpdateDTO.getAdditionalFieldsAddDTOList();
        String customTemplateId = customTemplateUpdateDTO.getId();
        CustomTemplateDO customTemplateDO1 = selectDOById(customTemplateId);
        // 如果是系统模板，设置为默认
        if (TYPE_SYSTEM.equals(customTemplateUpdateDTO.getType())) {
            customTemplateUpdateDTO.setIsDefault(true);
        }
        // 如果是系统默认模板需要新建一套,不是的话修改
        if (Boolean.TRUE.equals(customTemplateDO1.getIsDefault())
                && HrConstants.DEFAULT.equals(customTemplateDO1.getCompanyId())
                && TYPE_SYSTEM.equals(customTemplateDO1.getType())) {
            CustomTemplateAddDTO customTemplateAddDTO = BeanCopyUtil.beanCopy(customTemplateUpdateDTO, CustomTemplateAddDTO.class);
            customTemplateAddDTO.setIsDefault(true);
            customTemplateAddDTO.setCompanyId(customTemplateUpdateDTO.getCompanyId());

            // 查询是否有开启的模板，没有设为开启
            List<CustomTemplateDO> customTemplateDOS = selectOpen(customTemplateUpdateDTO.getCompanyId(), customTemplateAddDTO.getModuleCode(), tokenUser);
            customTemplateAddDTO.setIsOpen(CollectionUtils.isEmpty(customTemplateDOS));
            CustomTemplateVO customTemplateVO = saveTemplate(customTemplateAddDTO, tokenUser);
            // 重新启用新建的模板，将新字段写入员工设置
            open(customTemplateUpdateDTO.getCompanyId(), customTemplateVO.getId(), tokenUser);
            return 1;
        }

        // 校验
        checkTemplateForUpdate(customTemplateUpdateDTO, tokenUser);
        // 删除之前的模板字段
        customTemplateFieldService.deleteByTemplateIdList(Collections.singletonList(customTemplateId), tokenUser);
        // 删除之前的自定义模板字段
        companyAdditionalFieldsService.deleteByTemplateIdList(Collections.singletonList(customTemplateId), tokenUser);

        CustomTemplateDO customTemplateDO = customTemplateUpdateDTO.to(CustomTemplateDO.class);
        int count = updateByIdSelective(customTemplateDO, tokenUser.getSiteId(), tokenUser.getUserId());
        // 保存模板字段
        customTemplateFieldService.batchSave(customTemplateUpdateDTO.getId(), fieldAddDTOList, tokenUser);
        // 保存自定义模板字段
        if (!CollectionUtils.isEmpty(additionalFieldsAddDTOList)) {
            for (CompanyAdditionalFieldsAddDTO companyAdditionalFieldsAddDTO : additionalFieldsAddDTOList) {
                companyAdditionalFieldsAddDTO.setTemplateId(customTemplateId);
                companyAdditionalFieldsService.saveForCustom(companyAdditionalFieldsAddDTO, tokenUser);
            }
        }
        // 如果是已启用的模板，重新启用，将新字段写入员工设置
        CustomTemplateVO customTemplateVO = selectOpenTemplate(customTemplateUpdateDTO.getModuleCode(),
                customTemplateUpdateDTO.getCompanyId(), tokenUser);
        if (customTemplateVO != null) {
            if (customTemplateUpdateDTO.getId().equals(customTemplateVO.getId())) {
                open(customTemplateUpdateDTO.getCompanyId(), customTemplateId, tokenUser);
            }
        }
        return count;
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int update2(CustomTemplateUpdateDTO customTemplateUpdateDTO, TokenUser tokenUser) {
        // 系统字段
        List<CustomTemplateFieldAddDTO> fieldAddDTOList = customTemplateUpdateDTO.getCustomFieldAddDTOList();
        // 自定义字段
        List<CompanyAdditionalFieldsAddDTO> additionalFieldsAddDTOList = customTemplateUpdateDTO.getAdditionalFieldsAddDTOList();
        String customTemplateId = customTemplateUpdateDTO.getId();
        CustomTemplateDO customTemplateDO1 = selectDOById(customTemplateId);
        // 如果是系统模板，设置为默认
        if (TYPE_SYSTEM.equals(customTemplateUpdateDTO.getType())) {
            customTemplateUpdateDTO.setIsDefault(true);
        }
        // 如果是系统默认模板需要新建一套,不是的话修改
        if (Boolean.TRUE.equals(customTemplateDO1.getIsDefault())
                && HrConstants.DEFAULT.equals(customTemplateDO1.getCompanyId())
                && TYPE_SYSTEM.equals(customTemplateDO1.getType())) {
            CustomTemplateAddDTO customTemplateAddDTO = BeanCopyUtil.beanCopy(customTemplateUpdateDTO, CustomTemplateAddDTO.class);
            customTemplateAddDTO.setIsDefault(true);
            customTemplateAddDTO.setCompanyId(customTemplateUpdateDTO.getCompanyId());

            // 查询是否有开启的模板，没有设为开启
            List<CustomTemplateDO> customTemplateDOS = selectOpen(customTemplateUpdateDTO.getCompanyId(), customTemplateAddDTO.getModuleCode(), tokenUser);
            customTemplateAddDTO.setIsOpen(CollectionUtils.isEmpty(customTemplateDOS));
            // 可选字段取用花名册,不校验自定义字段
            CustomTemplateVO customTemplateVO = saveTemplate2(customTemplateAddDTO, tokenUser);
            // 重新启用新建的模板，将新字段写入员工设置
            open2(customTemplateUpdateDTO.getCompanyId(), customTemplateVO.getId(), tokenUser);
            return 1;
        }

        // 校验
        checkTemplateForUpdate(customTemplateUpdateDTO, tokenUser);
        // 删除之前的模板字段
        customTemplateFieldService.deleteByTemplateIdList(Collections.singletonList(customTemplateId), tokenUser);
        // 删除之前的自定义模板字段
        companyAdditionalFieldsService.deleteByTemplateIdList(Collections.singletonList(customTemplateId), tokenUser);

        CustomTemplateDO customTemplateDO = customTemplateUpdateDTO.to(CustomTemplateDO.class);
        int count = updateByIdSelective(customTemplateDO, tokenUser.getSiteId(), tokenUser.getUserId());
        // 保存模板字段
        customTemplateFieldService.batchSave(customTemplateUpdateDTO.getId(), fieldAddDTOList, tokenUser);
        // 保存自定义模板字段
        if (!CollectionUtils.isEmpty(additionalFieldsAddDTOList)) {
            for (CompanyAdditionalFieldsAddDTO companyAdditionalFieldsAddDTO : additionalFieldsAddDTOList) {
                companyAdditionalFieldsAddDTO.setTemplateId(customTemplateId);
                companyAdditionalFieldsService.saveForCustom2(companyAdditionalFieldsAddDTO, tokenUser);
            }
            // 用工单位级别-模板保存 仅本用工单位同步
//            // 租户级默认模板新增自定义 所有用工单位新增自定义字段
//            if ("site".equals(customTemplateUpdateDTO.getCompanyId()) && customTemplateUpdateDTO.getIsDefault()) {
//                List<CompanyDO> companyDOList = companyService.selectBySiteId(tokenUser.getSiteId());
//                List<CompanyAdditionalFieldsDO> companyAdditionalFieldsDOList = new ArrayList<>();
//                for (CompanyDO companyDO : companyDOList) {
//                    List<CompanyAdditionalFieldsDO> companyAdditionalFieldsList = additionalFieldsAddDTOList
//                            .parallelStream().map(companyAdditionalFieldsAddDTO -> {
//                                CompanyAdditionalFieldsDO companyAdditionalFieldsDO
//                                        = companyAdditionalFieldsAddDTO.to(CompanyAdditionalFieldsDO.class);
//                                // 放入用工单位Id
//                                companyAdditionalFieldsDO.setCompanyId(companyDO.getId());
//                                return companyAdditionalFieldsDO;
//                            }).collect(Collectors.toList());
//                    companyAdditionalFieldsDOList.addAll(companyAdditionalFieldsList);
//                }
//                companyAdditionalFieldsService.listCopyForCustom(companyAdditionalFieldsDOList, tokenUser);
//            }
        }
        // 如果是已启用的模板，重新启用，将新字段写入员工设置
        CustomTemplateVO customTemplateVO = selectOpenTemplate(customTemplateUpdateDTO.getModuleCode(),
                customTemplateUpdateDTO.getCompanyId(), tokenUser);
        if (customTemplateVO != null) {
            if (customTemplateUpdateDTO.getId().equals(customTemplateVO.getId())) {
                open2(customTemplateUpdateDTO.getCompanyId(), customTemplateId, tokenUser);
            }
        }
        return count;
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int deleteByIds(TokenUser tokenUser, String... customTemplateIds) {
        // 删除系统字段
        customTemplateFieldService.deleteByTemplateIdList(Arrays.asList(customTemplateIds), tokenUser);
        // 删除自定义字段
        companyAdditionalFieldsService.deleteByTemplateIdList(Arrays.asList(customTemplateIds), tokenUser);
        return logicalDeleteByIds(tokenUser.getSiteId(), tokenUser.getUserId(), (Object[]) customTemplateIds);
    }


    @Override
    public CustomTemplateVO selectById(String customTemplateId, String siteId) {
        CustomTemplateDO customTemplateDO = selectDOById(customTemplateId);
        if (customTemplateDO == null) {
            return null;
        }
        return customTemplateDO.to(CustomTemplateVO.class);
    }

    @Override
    public List<CustomTemplateListVO> select(CustomTemplateQuery customTemplateQuery, String siteId) {
        List<CustomTemplateDO> customTemplateDOList = selectDO(customTemplateQuery, siteId);
        if (CollectionUtils.isEmpty(customTemplateDOList)) {
            return customTemplateDOList == null ? null : new ArrayList<>();
        }
        return customTemplateDOList.stream()
                .map(customTemplateDO -> customTemplateDO.to(CustomTemplateListVO.class))
                .collect(Collectors.toList());
    }

    @Override
    public List<CustomTemplateDO> selectBySystem(String name, String moduleCode) {
        Example example = new Example(CustomTemplateDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", HrConstants.DEFAULT)
                .andEqualTo("isDefault", true)
                .andEqualTo("type", TYPE_SYSTEM);
        if (StrKit.isNotEmpty(name)) {
            example.and()
                    .andLike("name", "%" + name + "%")
                    .orLike("editBy", "%" + name + "%");
        }
        if (StrKit.isNotEmpty(moduleCode)) {
            example.and().andEqualTo("moduleCode", moduleCode);
        }
        example.orderBy("gmtCreate").desc();
        return customTemplateDAO.selectByExample(example);
    }

    @Override
    public List<CustomTemplateDO> selectDefaultBySite(String siteId) {
        Example example = new Example(CustomTemplateDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId)
                .andEqualTo("isDefault", true)
                .andEqualTo("companyId", "site");
        return customTemplateDAO.selectByExample(example);
    }

    @Override
    public List<CustomTemplateDO> selectAllDefaultBySite(String siteId) {
        Example example = new Example(CustomTemplateDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId)
                .andEqualTo("isDefault", true);
        return customTemplateDAO.selectByExample(example);
    }

    @Override
    public List<CustomTemplateDO> selectBySiteId(String name, String moduleCode, TokenUser tokenUser) {
        Example example = new Example(CustomTemplateDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", tokenUser.getSiteId())
                .andEqualTo("type", TYPE_SITE);
        if (StrKit.isNotEmpty(name)) {
            example.and()
                    .andLike("name", "%" + name + "%")
                    .orLike("editBy", "%" + name + "%");
        }
        if (StrKit.isNotEmpty(moduleCode)) {
            example.and().andEqualTo("moduleCode", moduleCode);
        }
        example.orderBy("gmtCreate").desc();
        return customTemplateDAO.selectByExample(example);
    }

    @Override
    public List<CustomTemplateDO> selectByCompanyId(String companyId, String name, String moduleCode, TokenUser tokenUser) {
        Example example = new Example(CustomTemplateDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", tokenUser.getSiteId())
                .andEqualTo("companyId", companyId)
                .andEqualTo("type", TYPE_COMPANY);
        if (StrKit.isNotEmpty(name)) {
            example.and()
                    .andLike("name", "%" + name + "%")
                    .orLike("editBy", "%" + name + "%");
        }
        if (StrKit.isNotEmpty(moduleCode)) {
            example.and().andEqualTo("moduleCode", moduleCode);
        }
        example.orderBy("gmtCreate").desc();
        return customTemplateDAO.selectByExample(example);
    }

    @Override
    public List<CustomTemplateDO> selectByCompanyIdAndName(String companyId, String name, String moduleCode, TokenUser tokenUser) {
        Example example = new Example(CustomTemplateDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", tokenUser.getSiteId())
                .andEqualTo("companyId", companyId)
                .andEqualTo("type", TYPE_COMPANY);
        if (StrKit.isNotEmpty(name)) {
            example.and().andEqualTo("name", name);
        }
        if (StrKit.isNotEmpty(moduleCode)) {
            example.and().andEqualTo("moduleCode", moduleCode);
        }
        example.orderBy("gmtCreate").desc();
        return customTemplateDAO.selectByExample(example);
    }

    @Override
    public int selectCount(CustomTemplateQuery customTemplateQuery, String siteId) {
        Example example = buildExample(customTemplateQuery, siteId);
        return customTemplateDAO.selectCountByExample(example);
    }

    @Override
    public Page<CustomTemplateListVO> selectPage(CustomTemplateQuery customTemplateQuery, TokenUser tokenUser) {
        List<CustomTemplateVO> list = select(customTemplateQuery.getName(), customTemplateQuery.getModuleCode(),
                customTemplateQuery.getCompanyId(), customTemplateQuery.getType(), tokenUser);
        Page<CustomTemplateVO> page = PageKit.startPage(list, customTemplateQuery.getPageNo(), customTemplateQuery.getPageSize());

        return page.to(CustomTemplateListVO.class);
    }

    @Override
    public List<CustomTemplateVO> select(String name, String moduleCode, String companyId, Integer type, TokenUser tokenUser) {
        List<CustomTemplateDO> list = new ArrayList<>();
        // 系统模板
        List<CustomTemplateDO> systemList = selectBySystem(name, moduleCode);
        // 租户/用工单位模板
        List<CustomTemplateDO> selfList = new ArrayList<>();
        // 查询租户
        if (TYPE_SITE.equals(type)) {
            // 租户模板
            selfList = selectBySiteId(name, moduleCode, tokenUser);
        }
        // 查询用工单位
        else if (TYPE_COMPANY.equals(type)) {
            // 用工单位模板
            selfList = selectByCompanyId(companyId, name, moduleCode, tokenUser);
        }

        // 如果没有租户设置的默认模板，返回内容加入系统默认模板
        boolean hasDefault = hasDefault(selfList);
        if (!hasDefault) {
            List<CustomTemplateDO> openList = new ArrayList<>();
            // 如果检索名称为空，不需要重新查询
            if (StrKit.isEmpty(name)) {
                openList = selfList;
            }
            // 查询租户
            else if (TYPE_SITE.equals(type)) {
                // 租户模板
                openList = selectBySiteId(null, moduleCode, tokenUser);
            }
            // 查询用工单位
            else if (TYPE_COMPANY.equals(type)) {
                // 用工单位模板
                openList = selectByCompanyId(companyId, null, moduleCode, tokenUser);
            }
            List<CustomTemplateDO> customTemplateDOS = selectOpen(openList);
            if (!CollectionUtils.isEmpty(systemList)) {
                // 查询是否有开启的，没有的话将默认设为开启
                CustomTemplateDO customTemplateDO = systemList.get(0);
                if (CollectionUtils.isEmpty(customTemplateDOS)) {
                    // 手动开启
                    customTemplateDO.setIsOpen(true);
                }
                list.add(customTemplateDO);
            } else {
                list.addAll(systemList);
            }
        }
        list.addAll(selfList);

        if (CollectionUtils.isEmpty(list)) {
            return new ArrayList<>();
        }
        return list.stream().map(s -> s.to(CustomTemplateVO.class)).collect(Collectors.toList());
    }

    /**
     * 是否包含初始模板（is_default == true）
     */
    private boolean hasDefault(List<CustomTemplateDO> customTemplateDOList) {
        for (CustomTemplateDO customTemplateDO : customTemplateDOList) {
            if (Boolean.TRUE.equals(customTemplateDO.getIsDefault())) {
                return true;
            }
        }
        return false;
    }

    /**
     * 是否包含同名模板
     *
     * @param name       校验的模板名
     * @param moduleCode 模块code
     * @param companyId  用工单位id
     * @param type       类型，租户/用工单位
     * @param tokenUser  当前用户
     * @return 1：是 0：否
     */
    private boolean hasSameName(String name, String moduleCode, String companyId, Integer type, TokenUser tokenUser) {
        // 包含默认模板
        List<CustomTemplateVO> customTemplateVOList = select(null, moduleCode, companyId, type, tokenUser);
        if (!CollectionUtils.isEmpty(customTemplateVOList)) {
            for (CustomTemplateVO customTemplateVO : customTemplateVOList) {
                if (name.equals(customTemplateVO.getName())) {
                    return true;
                }
            }
        }
        return false;
    }


    @Override
    public CustomTemplateDO selectDOById(String customTemplateId) {
        Example example = new Example(CustomTemplateDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("id", customTemplateId);
        return customTemplateDAO.selectOneByExample(example);
    }

    @Override
    public List<CustomTemplateDO> selectDO(CustomTemplateQuery customTemplateQuery, String siteId) {
        Example example = buildExample(customTemplateQuery, siteId);
        return customTemplateDAO.selectByExample(example);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int open(String companyId, String templateId, TokenUser tokenUser) {
        CustomTemplateVO customTemplateVO = selectById(templateId, tokenUser.getSiteId());
        ParamException.notNull(customTemplateVO, "模板不存在");
        // 模块code
        String moduleCode = customTemplateVO.getModuleCode();
        List<CustomTemplateDO> customTemplateDOS;
        // 租户
        if (HrConstants.ADD_FIELD_COMPANY_SITE.equals(companyId)) {
            /*if (!CustomerModuleType.CHECK_IN.getValue().equals(customTemplateVO.getModuleCode())) {
                // 租户只能设置预登记
                throw new ParamException("租户只能设置预登记模板");
            }*/
            customTemplateDOS = selectBySiteId(null, moduleCode, tokenUser);
        } else {
            customTemplateDOS = selectByCompanyId(companyId, null, moduleCode, tokenUser);
        }
        if (CollectionUtils.isEmpty(customTemplateDOS)) {
            throw new ParamException("至少有一个开启的模板");
        }
        // 系统默认模板不能修改
        if (Boolean.TRUE.equals(customTemplateVO.getIsDefault()
                && TYPE_SYSTEM.equals(customTemplateVO.getType())
                && HrConstants.DEFAULT.equals(customTemplateVO.getCompanyId()))) {
            log.info("开启系统默认模板，templateId：{}", templateId);
            // 关闭正在使用的模板
            // 系统默认模板不会有自定义字段
            closeOpenedTemplate(companyId, templateId, moduleCode, tokenUser);
            return 1;
        }
        // 没有开启的直接开启，有开启的先关闭之前的再开启
        Integer integer = openTemplate(companyId, templateId, moduleCode, tokenUser);
        // 将开启的模板复制到员工设置，templateId=null
        List<CompanyAdditionalFieldsDO> companyAdditionalFieldsDOS = companyAdditionalFieldsService.listByTemplateId(templateId, tokenUser);
        companyAdditionalFieldsService.listCopyForCustom(companyAdditionalFieldsDOS, tokenUser);
        return integer;
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int open2(String companyId, String templateId, TokenUser tokenUser) {
        CustomTemplateVO customTemplateVO = selectById(templateId, tokenUser.getSiteId());
        ParamException.notNull(customTemplateVO, "模板不存在");
        // 模块code
        String moduleCode = customTemplateVO.getModuleCode();
        List<CustomTemplateDO> customTemplateDOS;
        // 租户
        if (HrConstants.ADD_FIELD_COMPANY_SITE.equals(companyId)) {
            /*if (!CustomerModuleType.CHECK_IN.getValue().equals(customTemplateVO.getModuleCode())) {
                // 租户只能设置预登记
                throw new ParamException("租户只能设置预登记模板");
            }*/
            customTemplateDOS = selectBySiteId(null, moduleCode, tokenUser);
        } else {
            customTemplateDOS = selectByCompanyId(companyId, null, moduleCode, tokenUser);
        }
        if (CollectionUtils.isEmpty(customTemplateDOS)) {
            throw new ParamException("至少有一个开启的模板");
        }
        // 系统默认模板不能修改
        if (Boolean.TRUE.equals(customTemplateVO.getIsDefault()
                && TYPE_SYSTEM.equals(customTemplateVO.getType())
                && HrConstants.DEFAULT.equals(customTemplateVO.getCompanyId()))) {
            log.info("开启系统默认模板，templateId：{}", templateId);
            // 关闭正在使用的模板
            // 系统默认模板不会有自定义字段
            closeOpenedTemplate(companyId, templateId, moduleCode, tokenUser);
            return 1;
        }
        // 没有开启的直接开启，有开启的先关闭之前的再开启
        return openTemplate(companyId, templateId, moduleCode, tokenUser);
        // 模板可选字段直接使用花名册字段 不需要重复保存
//        // 将开启的模板复制到员工设置，templateId=null
//        List<CompanyAdditionalFieldsDO> companyAdditionalFieldsDOS = companyAdditionalFieldsService.listByTemplateId(templateId, tokenUser);
//        companyAdditionalFieldsService.listCopyForCustom(companyAdditionalFieldsDOS, tokenUser);
//        return integer;
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int close(String templateId, TokenUser tokenUser) {
        CustomTemplateDO customTemplateDO = selectDOById(templateId);
        CustomTemplateUpdateDTO updateDTO = new CustomTemplateUpdateDTO();
        updateDTO.setId(templateId);
        updateDTO.setIsOpen(false);
        return updateByIdSelective(updateDTO.to(CustomTemplateDO.class), customTemplateDO.getSiteId(), customTemplateDO.getCreateUserId());
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int closeByTemplateIdList(List<String> templateIdList, TokenUser tokenUser) {
        if (CollectionUtils.isEmpty(templateIdList)) {
            return 0;
        }
        CustomTemplateDO customTemplateDO = new CustomTemplateDO();
        customTemplateDO.setIsOpen(false);
        Example example = new Example(CustomTemplateDO.class);
        example.and()
                .andIn("id", templateIdList)
                .andEqualTo("valid", true)
                .andEqualTo("siteId", tokenUser.getSiteId());

        return customTemplateDAO.updateByExampleSelective(customTemplateDO, example);
    }

    /**
     * 开启模板并关闭之前已开启的模板
     */
    private Integer openTemplate(String companyId, String templateId, String moduleCode, TokenUser tokenUser) {
        // 关闭已开启的模板
        closeOpenedTemplate(companyId, templateId, moduleCode, tokenUser);

        CustomTemplateDO customTemplateDO = selectDOById(templateId);

        CustomTemplateUpdateDTO updateDTO = new CustomTemplateUpdateDTO();
        updateDTO.setId(templateId);
        updateDTO.setIsOpen(true);
        return updateByIdSelective(updateDTO.to(CustomTemplateDO.class), customTemplateDO.getSiteId(), customTemplateDO.getCreateUserId());
    }

    /**
     * 关闭之前已开启的模板
     *
     * @param companyId  用工单位id
     * @param templateId 模板id
     * @param moduleCode 模块code
     * @param tokenUser  当前用户
     * @return 关闭数量
     */
    private Integer closeOpenedTemplate(String companyId, String templateId, String moduleCode, TokenUser tokenUser) {
        List<CustomTemplateDO> customTemplateDOS = selectOpen(companyId, moduleCode, tokenUser);
        if (!CollectionUtils.isEmpty(customTemplateDOS)) {
            List<String> idList = customTemplateDOS.parallelStream()
                    .map(CustomTemplateDO::getId)
                    .collect(Collectors.toList());
            return closeByTemplateIdList(idList, tokenUser);
        }
        return 0;
    }

    @Override
    public List<CustomTemplateDO> selectOpen(String companyId, String moduleCode, TokenUser tokenUser) {
        List<CustomTemplateDO> customTemplateDOS;
        // 查询租户的
        if (HrConstants.ADD_FIELD_COMPANY_SITE.equals(companyId)) {
            // 查询租户
            customTemplateDOS = selectBySiteId(null, moduleCode, tokenUser);
        } else {
            // 查询用工单位
            customTemplateDOS = selectByCompanyId(companyId, null, moduleCode, tokenUser);
        }

        return selectOpen(customTemplateDOS);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int deleteById(TokenUser tokenUser, String customTemplateId) {
        CustomTemplateVO customTemplateVO = selectById(customTemplateId, tokenUser.getSiteId());
        if (Boolean.TRUE.equals(customTemplateVO.getIsDefault()
                && TYPE_SYSTEM.equals(customTemplateVO.getType())
                && HrConstants.DEFAULT.equals(customTemplateVO.getCompanyId()))) {
            throw new ParamException("系统模板不允许删除");
        }
        if (Boolean.TRUE.equals(customTemplateVO.getIsOpen())) {
            throw new ParamException("已启用的模板不允许删除");
        }
        return deleteByIds(tokenUser, customTemplateId);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public CustomTemplateVO saveTemplate(CustomTemplateAddDTO customTemplateAddDTO, TokenUser tokenUser) {
        long l = System.currentTimeMillis();
        checkTemplateForAdd(customTemplateAddDTO, tokenUser);
        long l1 = System.currentTimeMillis();
        log.info("校验数据，耗时：{} ms", l1 - l);

        // 保存自定义模板
        CustomTemplateVO save = save(customTemplateAddDTO, tokenUser);
        // 模板id
        String templateId = save.getId();
        long l2 = System.currentTimeMillis();
        log.info("保存自定义模板，耗时：{} ms", l2 - l1);

        // 保存模板字段
        customTemplateFieldService.batchSave(templateId, customTemplateAddDTO.getCustomFieldAddDTOList(), tokenUser);
        long l3 = System.currentTimeMillis();
        log.info("保存模板系统字段，耗时：{} ms", l3 - l2);

        //  保存自定义添加字段
        List<CompanyAdditionalFieldsAddDTO> additionalFieldsAddDTOList = customTemplateAddDTO.getAdditionalFieldsAddDTOList();
        if (!CollectionUtils.isEmpty(additionalFieldsAddDTOList)) {
            for (CompanyAdditionalFieldsAddDTO companyAdditionalFieldsAddDTO : additionalFieldsAddDTOList) {
                companyAdditionalFieldsAddDTO.setTemplateId(templateId);
                companyAdditionalFieldsService.saveForCustom2(companyAdditionalFieldsAddDTO, tokenUser);
            }
        }
        long l4 = System.currentTimeMillis();
        log.info("保存模板自定义添加字段，耗时：{} ms", l4 - l3);

        return save;
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public CustomTemplateVO saveTemplate2(CustomTemplateAddDTO customTemplateAddDTO, TokenUser tokenUser) {
        long l = System.currentTimeMillis();
        checkTemplateForAdd(customTemplateAddDTO, tokenUser);
        long l1 = System.currentTimeMillis();
        log.info("校验数据，耗时：{} ms", l1 - l);

        // 保存自定义模板
        CustomTemplateVO save = save(customTemplateAddDTO, tokenUser);
        // 模板id
        String templateId = save.getId();
        long l2 = System.currentTimeMillis();
        log.info("保存自定义模板，耗时：{} ms", l2 - l1);

        // 保存模板字段
        customTemplateFieldService.batchSave(templateId, customTemplateAddDTO.getCustomFieldAddDTOList(), tokenUser);
        long l3 = System.currentTimeMillis();
        log.info("保存模板系统字段，耗时：{} ms", l3 - l2);

        //  保存自定义添加字段
        List<CompanyAdditionalFieldsAddDTO> additionalFieldsAddDTOList = customTemplateAddDTO.getAdditionalFieldsAddDTOList();
        if (!CollectionUtils.isEmpty(additionalFieldsAddDTOList)) {
            for (CompanyAdditionalFieldsAddDTO companyAdditionalFieldsAddDTO : additionalFieldsAddDTOList) {
                companyAdditionalFieldsAddDTO.setTemplateId(templateId);
                // 不校验自定义字段
                companyAdditionalFieldsService.saveForCustom2(companyAdditionalFieldsAddDTO, tokenUser);
            }
        }
        long l4 = System.currentTimeMillis();
        log.info("保存模板自定义添加字段，耗时：{} ms", l4 - l3);

        return save;
    }

    @Override
    public List<CustomTemplateVO> selectSameNameTemplate(String name, String moduleCode, String companyId, Integer type,
                                                         Boolean isIssue, TokenUser tokenUser) {
        List<CustomTemplateVO> list = new ArrayList<>();
        List<CustomTemplateVO> customTemplateVOList = select(null, moduleCode, companyId, type, tokenUser);
        if (!CollectionUtils.isEmpty(customTemplateVOList)) {
            for (CustomTemplateVO customTemplateVO : customTemplateVOList) {
                if (isIssue.equals(customTemplateVO.getIsIssue()) && name.equals(customTemplateVO.getName())) {
                    list.add(customTemplateVO);
                }
            }
        }
        return list;
    }

    @Override
    @Async
    public void asyncIssueTemplate(CustomDTO customDTO, TokenUser tokenUser) {
        String key = CacheKeyKit.getIssueTemplate(tokenUser.getSiteId());
        RLock lock = redissonClient.getLock(key);
        boolean hasLock;
        try {
            // 加锁，等待0秒，上锁以后1小时自动解锁
            hasLock = lock.tryLock(0, 1, TimeUnit.HOURS);
            if (!hasLock) {
                throw new HrException("正在下发入职模板，请稍后操作");
            }
        } catch (InterruptedException e) {
            log.error("租户下发入职模板加锁异常：", e);
            throw new RuntimeException(e);
        }
        List<String> companyIdList = customDTO.getCompanyIdList();
        Map<String, SiteDO> siteMap = adminProviderService.selectSiteMap();
        SiteDO siteDO = siteMap.get(tokenUser.getSiteId());
        ParamException.notNull(siteDO, "登录租户已失效，请重新登录");
        //记录任务
        AsyncTaskDO asyncTaskDO = new AsyncTaskDO();
        asyncTaskDO.setTaskName("租户：【" + siteDO.getName() + "】-批量下发入职模板-"
                + DateKit8.format(new Date(), "yyyy-MM-dd HH:mm"));
        asyncTaskDO.setTaskStart(new Date());
        asyncTaskDO.setTotalTask(companyIdList.size());
        asyncTaskDO.setTaskStatus(TaskStatusEnum.JIN_XING_ZHONG.getValue());
        asyncTaskDO.setTaskType(AsyncTaskTypeEnum.ISSUE_TEMPLATE.getValue());
        asyncTaskDO.setTaskMethod("asyncIssueTemplate");
        asyncTaskDO = asyncTaskService.save(asyncTaskDO, tokenUser.getSiteId(), tokenUser.getUserId());
        String taskId = asyncTaskDO.getId();
        CountDownLatch countDownLatch = new CountDownLatch(companyIdList.size());
        for (String companyId : companyIdList) {
            long time = System.currentTimeMillis();
            AsyncTaskDetailDO asyncTaskDetailDO = new AsyncTaskDetailDO();
            asyncTaskDetailDO.setTaskId(asyncTaskDO.getId());
            asyncTaskDetailDO.setSubjectId(companyId);
            log.info("线程名称：{},异步下发入职模板,用工单位id：{}", Thread.currentThread().getName(), companyId);
            try {
                // 子任务
                customDTO.setCompanyIdList(Collections.singletonList(companyId));
                issueTemplate(customDTO, tokenUser);
                // 完成一个子任务，记录一下
                asyncTaskDetailDO.setSubjectResult(TaskSubjectResultEnum.SUCCESS.getValue());
            } catch (Exception e) {
                log.error("线程名称：{},异步发起合同异常,用工单位id{}，用时：{}, 异常{}"
                        , Thread.currentThread().getName(), companyId, System.currentTimeMillis() - time, e);
                log.error("异步调用公司合同签署异常：", e);
                asyncTaskDetailDO.setSubjectResult(TaskSubjectResultEnum.FAIL.getValue());
                asyncTaskDetailDO.setErrorMessage(e.getMessage());
                asyncTaskService.taskFail(taskId);
            } finally {
                asyncTaskDetailService.save(asyncTaskDetailDO, tokenUser.getSiteId(), tokenUser.getUserId());
                asyncTaskService.finishSubTask(taskId);
                countDownLatch.countDown();
                log.info("线程名称：{},异步发起合同结束,用工单位id{}，用时：{}"
                        , Thread.currentThread().getName(), companyId, System.currentTimeMillis() - time);
            }
        }
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        lock.unlock();
        log.info("线程名称：{},异步租户下发入职模板结束,公司名称：{}", Thread.currentThread().getName(), siteDO.getName());
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public Integer issueTemplate(CustomDTO customDTO, TokenUser tokenUser) {
        List<String> companyIdList = customDTO.getCompanyIdList();
        ParamException.notEmpty(companyIdList, "用工单位不能为空");
        companyIdList = companyIdList
                .parallelStream()
                .distinct().collect(Collectors.toList());
        CustomTemplateDO customTemplateDO = selectDOById(customDTO.getTemplateId());
        ParamException.notNull(customTemplateDO, "下发模板不存在");
        // 下发的模板id
        String templateId = customTemplateDO.getId();
        CustomTemplateAddDTO templateAddDTO = customTemplateDO.to(CustomTemplateAddDTO.class);
        //花名册添加员工字段时校验是否和公司下社保子项重复
        CustomTemplateFieldQuery customTemplateFieldQuery = new CustomTemplateFieldQuery();
        customTemplateFieldQuery.setCompanyId("site");
        customTemplateFieldQuery.setTemplateId(customDTO.getTemplateId());
        List<CustomTemplateFieldListVO> select = customTemplateFieldService.select(customTemplateFieldQuery, tokenUser);
        // 系统默认模板
        templateAddDTO.setIsDefault(Boolean.TRUE.equals(customTemplateDO.getIsDefault()));
        int count = 0;
        long l = System.currentTimeMillis();
        for (String companyId : companyIdList) {
            templateAddDTO.setEditBy(tokenUser.getUserName());
            templateAddDTO.setIsIssue(true);
            templateAddDTO.setSourceId(templateId);
            templateAddDTO.setType(TYPE_COMPANY);
            templateAddDTO.setCompanyId(companyId);
            // 校验是否存在同名模板
            boolean hasSameName = hasSameName(templateAddDTO.getName(), templateAddDTO.getModuleCode(), companyId, TYPE_COMPANY, tokenUser);
            if (hasSameName) {
                CompanyVO companyVO = companyService.selectBaseCompanyById(companyId, tokenUser.getSiteId());
                throw new ParamException("用工单位【" + companyVO.getName() + "】已存在同名模板");
            }
            // 如果下发默认模板，默认开启
            if (Boolean.TRUE.equals(templateAddDTO.getIsDefault())) {
                // 查询该用工单位是否已经有默认模板
                List<CustomTemplateDO> customTemplateDOS = selectByCompanyId(companyId, null, templateAddDTO.getModuleCode(), tokenUser);
                boolean hasDefault = hasDefault(customTemplateDOS);
                if (hasDefault) {
                    CompanyVO companyVO = companyService.selectBaseCompanyById(companyId, tokenUser.getSiteId());
                    throw new ParamException("用工单位【" + companyVO.getName() + "】已存在默认模板");
                }
                templateAddDTO.setIsOpen(true);
            }
            // 保存模板
            CustomTemplateVO customTemplateVO = save(templateAddDTO, tokenUser);
            List<CustomTemplateFieldAddDTO> fieldAddDTOList = new ArrayList<>();
            // 系统字段
            List<CustomTemplateFieldVO> customTemplateFieldVOList = customTemplateFieldService.listByTemplateId(templateId, tokenUser);
            if (!CollectionUtils.isEmpty(customTemplateFieldVOList)) {
                fieldAddDTOList = customTemplateFieldVOList.stream()
                        .map(s -> {
                            CustomTemplateFieldAddDTO fieldAddDTO = s.to(CustomTemplateFieldAddDTO.class);
                            fieldAddDTO.setIsDefault(false);
                            fieldAddDTO.setCompanyId(companyId);
                            fieldAddDTO.setTemplateId(customTemplateVO.getId());
                            return fieldAddDTO;
                        })
                        .collect(Collectors.toList());

                templateAddDTO.setCustomFieldAddDTOList(fieldAddDTOList);
            }
            // 保存模板字段
            customTemplateFieldService.batchSave(fieldAddDTOList, tokenUser);
            // 自定义字段
            List<CompanyAdditionalFieldsDO> companyAdditionalFieldsDOS = companyAdditionalFieldsService.listByTemplateId(templateId, tokenUser);
            if (!CollectionUtils.isEmpty(companyAdditionalFieldsDOS)) {
                for (CompanyAdditionalFieldsDO companyAdditionalFieldsDO : companyAdditionalFieldsDOS) {
                    //模板字段校验是否和公司下社保子项重复
                    if (!CollectionUtils.isEmpty(select) && ("onJob".equals(select.get(0).getModuleCode()) || "waitJob".equals(select.get(0).getModuleCode()))) {
                        if (!CollectionUtils.isEmpty(customDTO.getCompanyIdList())) {
                            if (socProgService.checkEmpItemName(companyId, companyAdditionalFieldsDO.getFieldName(), tokenUser)) {
                                CompanyVO companyVO = companyService.selectBaseCompanyById(companyId, tokenUser.getSiteId());
                                if (companyVO != null) {
                                    throw new ParamException(companyVO.getName() + "公司下社保子项和此模板中存在相同的字段名【" + companyAdditionalFieldsDO.getFieldName() + "】");
                                }
                            }
                        }
                    }

                    CompanyAdditionalFieldsAddDTO additionalFieldsAddDTO = companyAdditionalFieldsDO.to(CompanyAdditionalFieldsAddDTO.class);
                    additionalFieldsAddDTO.setCompanyId(companyId);
                    additionalFieldsAddDTO.setTemplateId(customTemplateVO.getId());
                    // 模板保存自定义字段
                    companyAdditionalFieldsService.saveForCustom(additionalFieldsAddDTO, tokenUser);
                }
            }
            count++;
        }
        log.info("下发自定义模板，用工单位数量：{}，耗时：{}ms", companyIdList.size(), System.currentTimeMillis() - l);
        return count;
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public Integer issueTemplate2(CustomDTO customDTO, TokenUser tokenUser) {
        List<String> companyIdList = customDTO.getCompanyIdList();
        ParamException.notEmpty(companyIdList, "未选择需要下发的用工单位");
        List<String> templateIdList = customDTO.getTemplateIdList();
        if (CollectionUtils.isEmpty(templateIdList)) {
            ParamException.notNull(customDTO.getTemplateId(), "未选择下发模板");
            templateIdList = Collections.singletonList(customDTO.getTemplateId());
        }
        for (String companyId : companyIdList) {
            // 先将所有用工单位自定义字段同步到目标用工单位中
//            issuedAdditionalFields(companyId, tokenUser);
            for (String templateId : templateIdList) {
                // 下发单个模板到指定用工单位
                issueTemplateOne(companyId, templateId, tokenUser);
            }
        }
        return companyIdList.size();
    }

    @Override
    @Async
    public void asyncIssueTemplate2(CustomDTO customDTO, TokenUser tokenUser) {
        issueTemplate2(customDTO, tokenUser);
    }

    /**
     * 下发单个模板到指定用工单位
     *
     * @param companyId  用工单位Id
     * @param templateId 模板id
     */
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    void issueTemplateOne(String companyId, String templateId, TokenUser tokenUser) {
        CustomTemplateDO customTemplateDO = selectDOById(templateId);
        ParamException.notNull(customTemplateDO, "下发模板不存在");
        // 查询用工单位下同名模板 若不存在则需要新增
        List<CustomTemplateDO> customTemplateDOList = selectByCompanyIdAndName(companyId
                , customTemplateDO.getName(), customTemplateDO.getModuleCode(), tokenUser);
        // 用工单位模板中已选系统字段
        List<CustomTemplateFieldVO> companyFieldVOList = new ArrayList<>();
        // 用工单位模板中已选自定义字段
        List<CompanyAdditionalFieldsDO> companyFieldsDOList = new ArrayList<>();
        // 下发到用工单位模板Id
        String newTemplateId;
        // 用工单位不存在同名模板 新建
        if (CollectionUtils.isEmpty(customTemplateDOList)) {
            CustomTemplateAddDTO customTemplateAddDTO = customTemplateDO.to(CustomTemplateAddDTO.class);
            customTemplateAddDTO.setCompanyId(companyId);
            customTemplateAddDTO.setIsIssue(Boolean.TRUE);
            customTemplateAddDTO.setEditBy(tokenUser.getUserName());
            customTemplateAddDTO.setType(TYPE_COMPANY);
            customTemplateAddDTO.setSourceId(templateId);
            // 查询用工单位下有没有开启的模板 没有就开启
            List<CustomTemplateDO> allCustomTemplateDOList = selectByCompanyId(companyId
                    , null, customTemplateDO.getModuleCode(), tokenUser);
            customTemplateAddDTO.setIsOpen(allCustomTemplateDOList.parallelStream().noneMatch(CustomTemplateDO::getIsOpen));
            CustomTemplateVO save = save(customTemplateAddDTO, tokenUser);
            newTemplateId = save.getId();
        } else {
            CustomTemplateDO firstOne = customTemplateDOList.get(0);
            firstOne.setEditBy(tokenUser.getUserName());
            firstOne.setSourceId(templateId);
            updateByIdSelective(firstOne, firstOne.getSiteId(), tokenUser.getUserId());
            newTemplateId = firstOne.getId();
            companyFieldVOList = customTemplateFieldService.listByTemplateId(newTemplateId, tokenUser);
            companyFieldsDOList = companyAdditionalFieldsService.listByTemplateId(newTemplateId, tokenUser);
        }
        // 租户模板中系统字段
        List<CustomTemplateFieldVO> siteFieldVOList = customTemplateFieldService
                .listByTemplateId(templateId, tokenUser);
        // 租户模板含有字段
        List<String> fieldNameList = siteFieldVOList.parallelStream()
                .map(CustomTemplateFieldVO::getFieldName).collect(Collectors.toList());
        // 租户模板含有字段
        for (CustomTemplateFieldVO customTemplateFieldVO : siteFieldVOList) {
            boolean needSave = Boolean.TRUE;
            for (CustomTemplateFieldVO templateFieldVO : companyFieldVOList) {
                // 字段名称和模块都一致 视为同一字段 将租户设置放入用工单位模板中
                if (templateFieldVO.getModuleCode().equals(customTemplateFieldVO.getModuleCode())
                        && templateFieldVO.getFieldName().equals(customTemplateFieldVO.getFieldName())) {
                    CustomTemplateFieldDO customTemplateFieldDO = customTemplateFieldVO.to(CustomTemplateFieldDO.class);
                    customTemplateFieldDO.setId(templateFieldVO.getId());
                    customTemplateFieldDO.setCompanyId(companyId);
                    customTemplateFieldDO.setTemplateId(newTemplateId);
                    customTemplateFieldService.updateByIdSelective(customTemplateFieldDO, tokenUser.getSiteId(), tokenUser.getUserId());
                    needSave = Boolean.FALSE;
                    break;
                }
            }
            // 租户模板中字段在用工单位模板中不存在 新增
            if (needSave) {
                CustomTemplateFieldDO customTemplateFieldDO = customTemplateFieldVO.to(CustomTemplateFieldDO.class);
                customTemplateFieldDO.setCompanyId(companyId);
                customTemplateFieldDO.setTemplateId(newTemplateId);
                customTemplateFieldDO.setId(null);
                customTemplateFieldService.save(customTemplateFieldDO, tokenUser.getSiteId(), tokenUser.getUserId());
            }
        }
        for (CustomTemplateFieldVO customTemplateFieldVO : companyFieldVOList) {
            // 租户下发模板中不含有的字段 先关闭 为保留字段下的存值
            if (!fieldNameList.contains(customTemplateFieldVO.getFieldName())) {
                CustomTemplateFieldDO customTemplateFieldDO = customTemplateFieldVO.to(CustomTemplateFieldDO.class);
                customTemplateFieldDO.setIsOpen(Boolean.FALSE);
                customTemplateFieldService.updateByIdSelective(customTemplateFieldDO, tokenUser.getSiteId(), tokenUser.getUserId());
            }
        }
        // 租户模板中自定义字段
        List<CompanyAdditionalFieldsDO> siteFieldsDOList = companyAdditionalFieldsService
                .listByTemplateId(templateId, tokenUser);
        // 租户模板含有字段
        List<String> additionalFieldNameList = siteFieldsDOList.parallelStream()
                .map(CompanyAdditionalFieldsDO::getFieldName).collect(Collectors.toList());
        // 租户模板含有字段
        for (CompanyAdditionalFieldsDO companyAdditionalFieldsDO : siteFieldsDOList) {
            boolean needSave = Boolean.TRUE;
            for (CompanyAdditionalFieldsDO additionalFieldsDO : companyFieldsDOList) {
                // 字段名称和模块都一致 视为同一字段 将租户设置放入用工单位模板中
                if (additionalFieldsDO.getModuleCode().equals(companyAdditionalFieldsDO.getModuleCode())
                        && additionalFieldsDO.getFieldName().equals(companyAdditionalFieldsDO.getFieldName())) {
                    CompanyAdditionalFieldsDO companyAdditionalDO = companyAdditionalFieldsDO.to(CompanyAdditionalFieldsDO.class);
                    companyAdditionalDO.setId(additionalFieldsDO.getId());
                    companyAdditionalDO.setCompanyId(companyId);
                    companyAdditionalDO.setTemplateId(newTemplateId);
                    companyAdditionalFieldsService.updateByIdSelective(companyAdditionalDO
                            , tokenUser.getSiteId(), tokenUser.getUserId());
                    needSave = Boolean.FALSE;
                    break;
                }
            }
            // 租户模板中字段在用工单位模板中不存在 新增
            if (needSave) {
                CompanyAdditionalFieldsDO companyAdditionalDO = companyAdditionalFieldsDO.to(CompanyAdditionalFieldsDO.class);
                companyAdditionalDO.setCompanyId(companyId);
                companyAdditionalDO.setTemplateId(newTemplateId);
                companyAdditionalDO.setId(null);
                companyAdditionalFieldsService.save(companyAdditionalDO, tokenUser.getSiteId(), tokenUser.getUserId());
            }
        }
        for (CompanyAdditionalFieldsDO companyAdditionalFieldsDO : companyFieldsDOList) {
            // 租户下发模板中不含有的字段 先关闭 为保留字段下的存值
            if (!additionalFieldNameList.contains(companyAdditionalFieldsDO.getFieldName())) {
                CompanyAdditionalFieldsDO companyAdditionalDO = companyAdditionalFieldsDO.to(CompanyAdditionalFieldsDO.class);
                companyAdditionalDO.setIsOpen(Boolean.FALSE);
                companyAdditionalFieldsService.updateByIdSelective(companyAdditionalDO, tokenUser.getSiteId(), tokenUser.getUserId());
            }
        }
    }


    /**
     * 下发租户的可选自定义信息到用工单位 自用同时下发入职、待入职、预登记末班下的自定义字段
     *
     * @param companyId 用工单位Id
     * @param tokenUser 登录用户
     */
    private void issuedAdditionalFields2(String companyId, TokenUser tokenUser) {
        // 租户下自定义字段
        List<CompanyAdditionalFieldsListVO> siteAdditionalFieldsListVOList = companyAdditionalFieldsService
                .selectByCompanyId3("site", null, tokenUser.getSiteId());

        // 用工单位下自定义字段
        List<CompanyAdditionalFieldsListVO> companyAdditionalFieldsListVOList = companyAdditionalFieldsService
                .selectByCompanyId2(companyId, null, tokenUser.getSiteId());
        for (CompanyAdditionalFieldsListVO siteAdditionalFieldsListVO : siteAdditionalFieldsListVOList) {
            boolean needSave = Boolean.TRUE;
            for (CompanyAdditionalFieldsListVO companyAdditionalFieldsListVO : companyAdditionalFieldsListVOList) {
                // 字段名称和模块都一致 视为同一字段 将租户设置放入用工单位模板中
                if (companyAdditionalFieldsListVO.getModuleCode().equals(siteAdditionalFieldsListVO.getModuleCode())
                        && companyAdditionalFieldsListVO.getFieldName().equals(siteAdditionalFieldsListVO.getFieldName())) {
                    CompanyAdditionalFieldsDO companyAdditionalDO = siteAdditionalFieldsListVO.to(CompanyAdditionalFieldsDO.class);
                    companyAdditionalDO.setId(companyAdditionalFieldsListVO.getId());
                    companyAdditionalDO.setCompanyId(companyId);
                    companyAdditionalDO.setTemplateId(null);
                    companyAdditionalFieldsService.updateByIdSelective(companyAdditionalDO
                            , tokenUser.getSiteId(), tokenUser.getUserId());
                    needSave = Boolean.FALSE;
                    break;
                }
            }
            // 租户模板中字段在用工单位模板中不存在 新增
            if (needSave) {
                CompanyAdditionalFieldsDO companyAdditionalDO = siteAdditionalFieldsListVO.to(CompanyAdditionalFieldsDO.class);
                companyAdditionalDO.setCompanyId(companyId);
                companyAdditionalDO.setTemplateId(null);
                companyAdditionalDO.setId(null);
                // 下发可选字段 默认非必填
                companyAdditionalDO.setIsNecessary(Boolean.FALSE);
                companyAdditionalFieldsService.save(companyAdditionalDO, tokenUser.getSiteId(), tokenUser.getUserId());
            }
        }
    }

    @Override
    @Async
    public void issuedAllAdditionalFields() {
        Map<String, SiteDO> siteMap = adminProviderService.selectSiteMap();
        for (String siteId : siteMap.keySet()) {
            TokenUser tokenUser = new TokenUser("issuedAllAdditionalFields", siteId);
            List<CompanyDO> companyDOList = companyService.selectBySiteId(siteId);
            for (CompanyDO companyDO : companyDOList) {
                issuedAdditionalFields2(companyDO.getId(), tokenUser);
            }
        }

        log.info("issuedAllAdditionalFields方法执行完毕");
    }

    @Override
    @Async
    public void issuedAllAdditionalFields2() {
        Map<String, SiteDO> siteMap = adminProviderService.selectSiteMap();
        int num = 0;
        for (String siteId : siteMap.keySet()) {
            TokenUser tokenUser = new TokenUser("issuedAllAdditionalFields2", siteId);
            List<CompanyDO> companyDOList = companyService.selectBySiteId(siteId);
            // 租户下默认模板
            List<CustomTemplateDO> customTemplateDOList = selectDefaultBySite(siteId);
            // 查询租户下所有的默认模板
            List<CustomTemplateDO> allCustomTemplateDOList = selectAllDefaultBySite(siteId);
            // 默认模板按用工单位分组
            Map<String, List<CustomTemplateDO>> companyIdListMap = allCustomTemplateDOList.parallelStream().filter(customTemplateDO
                    -> customTemplateDO.getCompanyId() != null).collect(Collectors.groupingBy(CustomTemplateDO::getCompanyId));
            // 所有用工单位
            for (CompanyDO companyDO : companyDOList) {
                String companyId = companyDO.getId();
                // 用工单位创建的默认模板
                List<CustomTemplateDO> companyCustomTemplateDOList = companyIdListMap.get(companyId);
                // 租户下的默认模板
                for (CustomTemplateDO customTemplateDO : customTemplateDOList) {
                    // 只下发入职和待入职
                    List<String> moduleCodeList = new ArrayList<>(Arrays.asList("onJob", "waitJob"));
                    if (!moduleCodeList.contains(customTemplateDO.getModuleCode())) {
                        continue;
                    }
                    boolean needAdd = Boolean.TRUE;
                    String templateId = customTemplateDO.getId();
                    // 用工单位下不存在 就创建
                    if (CollectionUtils.isEmpty(companyCustomTemplateDOList)) {
                        issueTemplateOne(companyId, templateId, tokenUser);
                        num++;
                        continue;
                    }
                    for (CustomTemplateDO templateDO : companyCustomTemplateDOList) {
                        // 名称和模块一致 就认为是同一模板
                        if (templateDO.getName().equals(customTemplateDO.getName())
                                && templateDO.getModuleCode().equals(customTemplateDO.getModuleCode())) {
                            needAdd = false;
                            break;
                        }
                    }
                    if (needAdd) {
                        issueTemplateOne(companyId, templateId, tokenUser);
                        num++;
                    }
                }
            }
        }
        log.info("issuedAllAdditionalFields2方法执行完毕，新增条数：{}", num);
    }

    @Override
    @Async
    public void issuedAllAdditionalFields3(String templateId, List<String> companyIds, TokenUser tokenUser) {
        int num = 0;
        ParamException.notNull(templateId, "未选择需要下发的模板");
        if (CollectionUtils.isEmpty(companyIds)) {
            List<CompanyDO> companyDOList = companyService.selectBySiteId(tokenUser.getSiteId());
            ParamException.notEmpty(companyDOList, "没有需要下发的用工单位");
            companyIds = companyDOList.parallelStream().map(BaseDO::getId).distinct().collect(Collectors.toList());
        }
        for (String companyId : companyIds) {
            issueTemplateOne(companyId, templateId, tokenUser);
            num++;
        }
        log.info("issuedAllAdditionalFields3方法执行完毕，新增条数：{}", num);
    }

    @Override
    @Async
    public void repairCheckIn() {
        Map<String, SiteDO> siteMap = adminProviderService.selectSiteMap();
        int addNum = 0;
        int updateNum = 0;
        for (String siteId : siteMap.keySet()) {
            // 查询租户下所有自定义字段
            List<CompanyAdditionalFieldsListVO> companyAdditionalFieldsListVOList
                    = companyAdditionalFieldsService.selectByCompanyId2("site", null, siteId);
            TokenUser tokenUser = new TokenUser("repairCheckIn", siteId);
            List<CompanyAdditionalFieldsListVO> siteAdditionalFieldsListVOList
                    = companyAdditionalFieldsService.listByCompanyId("checkIn", "site", HrConstants.TEMPLATE_ID_LIST, tokenUser);
            for (CompanyAdditionalFieldsListVO companyAdditionalFieldsListVO : companyAdditionalFieldsListVOList) {
                boolean needAdd = Boolean.TRUE;
                for (CompanyAdditionalFieldsListVO additionalFieldsListVO : siteAdditionalFieldsListVOList) {
                    // 字段名称相同 且模块也一样 视为同一字段
                    if (companyAdditionalFieldsListVO.getFieldName().equals(additionalFieldsListVO.getFieldName())
                            && companyAdditionalFieldsListVO.getModuleCode().equals(additionalFieldsListVO.getModuleCode())) {
                        CompanyAdditionalFieldsDO updateDO = companyAdditionalFieldsListVO
                                .to(CompanyAdditionalFieldsDO.class);
                        updateDO.setId(additionalFieldsListVO.getId());
                        updateDO.setCompanyId("site");
                        updateDO.setModuleType("checkIn");
                        updateDO.setTemplateId(HrConstants.TEMPLATE_ID_LIST);
                        companyAdditionalFieldsService.updateByIdSelective(updateDO
                                , tokenUser.getSiteId(), tokenUser.getUserId());
                        updateNum++;
                        needAdd = Boolean.FALSE;
                        break;
                    }
                }
                if (needAdd) {
                    CompanyAdditionalFieldsDO saveDO = companyAdditionalFieldsListVO
                            .to(CompanyAdditionalFieldsDO.class);
                    saveDO.setId(null);
                    saveDO.setCompanyId("site");
                    saveDO.setModuleType("checkIn");
                    saveDO.setTemplateId(HrConstants.TEMPLATE_ID_LIST);
                    companyAdditionalFieldsService.save(saveDO
                            , tokenUser.getSiteId(), tokenUser.getUserId());
                    addNum++;
                }
            }
        }
        log.info("repairCheckIn执行完毕，新增条数：{}，修改条数：{}", addNum, updateNum);
    }

    @Override
    @Async
    public void repairNecessary() {
        Map<String, SiteDO> siteMap = adminProviderService.selectSiteMap();
        int addNum = 0;
        int updateNum = 0;
        // 系统级花名册基本字段
        List<CompanyNecessaryFieldDO> companyNecessaryFieldDOList = companyNecessaryFieldService.listBySystem();
        for (String siteId : siteMap.keySet()) {
            // 租户级花名册基本字段
            List<CompanyNecessaryFieldDO> necessaryFieldDOList = companyNecessaryFieldService.selectByCompanyId("site", siteId);
            for (CompanyNecessaryFieldDO companyNecessaryFieldDO : companyNecessaryFieldDOList) {
                boolean needAdd = Boolean.TRUE;
                for (CompanyNecessaryFieldDO necessaryFieldDO : necessaryFieldDOList) {
                    if (necessaryFieldDO.getFieldName().equals(companyNecessaryFieldDO.getFieldName())
                            && necessaryFieldDO.getModuleCode().equals(companyNecessaryFieldDO.getModuleCode())) {
                        CompanyNecessaryFieldDO updateDO = companyNecessaryFieldDO.to(CompanyNecessaryFieldDO.class);
                        updateDO.setId(necessaryFieldDO.getId());
                        updateDO.setCompanyId("site");
                        companyNecessaryFieldService.updateByIdSelective(updateDO, siteId, "repairNecessary");
                        updateNum++;
                        needAdd = Boolean.FALSE;
                        break;
                    }
                }
                if (needAdd) {
                    CompanyNecessaryFieldDO saveDO = companyNecessaryFieldDO.to(CompanyNecessaryFieldDO.class);
                    saveDO.setId(null);
                    saveDO.setCompanyId("site");
                    companyNecessaryFieldService.save(saveDO, siteId, "repairNecessary");
                    addNum++;
                }
            }
        }
        log.info("repairNecessary执行完毕，新增条数：{}，修改条数：{}", addNum, updateNum);
    }

    @Override
    @Async
    public void repairSiteAdditionalFields(String siteId) {
        Set<String> siteIds;
        if (StringUtils.isEmpty(siteId)) {
            Map<String, SiteDO> siteMap = adminProviderService.selectSiteMap();
            siteIds = siteMap.keySet();
        } else {
            siteIds = Collections.singleton(siteId);
        }
        for (String oneSiteId : siteIds) {
            // 抽取的自定义字段
            List<CompanyAdditionalFieldsListVO> companyAdditionalFieldsListVOList = companyAdditionalFieldsService
                    .selectByCompanyId4("site", null, oneSiteId);
            // 站点的自定义字段
            List<CompanyAdditionalFieldsListVO> companyAdditionalFieldsListList = companyAdditionalFieldsService
                    .selectByCompanyId2("site", null, oneSiteId);
            List<String> fieldNameList = companyAdditionalFieldsListList.parallelStream()
                    .map(CompanyAdditionalFieldsListVO::getFieldName).collect(Collectors.toList());
            List<CompanyAdditionalFieldsAddDTO> companyAdditionalFieldsAddDTOList = new ArrayList<>();
            for (CompanyAdditionalFieldsListVO companyAdditionalFieldsListVO : companyAdditionalFieldsListVOList) {
                if (!fieldNameList.contains(companyAdditionalFieldsListVO.getFieldName())) {
                    CompanyAdditionalFieldsAddDTO additionalFieldsAddDTO
                            = companyAdditionalFieldsListVO.to(CompanyAdditionalFieldsAddDTO.class);
                    additionalFieldsAddDTO.setCompanyId("site");
                    additionalFieldsAddDTO.setIsOpen(Boolean.TRUE);
                    companyAdditionalFieldsAddDTOList.add(additionalFieldsAddDTO);
                }
            }
            TokenUser tokenUser = new TokenUser("repairSiteAdditionalFields", oneSiteId);
            companyAdditionalFieldsService.batchSave(companyAdditionalFieldsAddDTOList, tokenUser);
        }
    }

    @Override
    public CustomTemplateVO selectOpenTemplate(String moduleCode, String companyId, TokenUser tokenUser) {
        SiteVO site = adminProviderService.selectSiteById(tokenUser.getSiteId(), tokenUser);
        // 查询租户
        if (CustomerModuleType.CHECK_IN.getValue().equals(moduleCode)) {
            if (!HrConstants.ADD_FIELD_COMPANY_SITE.equals(companyId)) {
                throw new ParamException("预登记模板只有租户使用");
            }
        }

        List<CustomTemplateDO> customTemplateDOS = selectOpen(companyId, moduleCode, tokenUser);
        CustomTemplateVO customTemplateVO;
        // 如果没有开启的，就返回系统默认模板
        if (CollectionUtils.isEmpty(customTemplateDOS)) {
            List<CustomTemplateDO> customTemplateDOS1 = selectBySystem(null, moduleCode);
            customTemplateVO = customTemplateDOS1.get(0).to(CustomTemplateVO.class);
        } else {
            customTemplateVO = customTemplateDOS.get(0).to(CustomTemplateVO.class);
        }
        // 开启的模板id
        String openTemplateId = customTemplateVO.getId();

        // 系统字段
        List<CustomTemplateFieldVO> customTemplateFieldVOList = customTemplateFieldService.listByTemplateId(openTemplateId, tokenUser);
        if (JIA_FANG_QY.equals(site.getSiteType()) || JIA_FANG_SY.equals(site.getSiteType())) {
            customTemplateFieldVOList = customTemplateFieldVOList
                    .stream().filter(field -> !"工作性质".equals(field.getFieldName()))
                    .collect(Collectors.toList());
        }
        customTemplateVO.setCustomTemplateFieldVOList(customTemplateFieldVOList);

        // 自定义字段
        List<CompanyAdditionalFieldsListVO> additionalFieldsListVOS = companyAdditionalFieldsService.listByCompanyId(null,
                companyId, null, tokenUser);
        // templateId = null
        List<CompanyAdditionalFieldsListVO> nullTemplateList = new ArrayList<>();
        // templateId = templateId
        List<CompanyAdditionalFieldsListVO> idTemplateList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(additionalFieldsListVOS)) {
            for (CompanyAdditionalFieldsListVO companyAdditionalFieldsListVO : additionalFieldsListVOS) {
                // 当前模板id
                String templateId = companyAdditionalFieldsListVO.getTemplateId();
                if (null == templateId) {
                    nullTemplateList.add(companyAdditionalFieldsListVO);
                } else if (openTemplateId.equals(templateId)) {
                    idTemplateList.add(companyAdditionalFieldsListVO);
                }
            }
        }

        // 如果开启的模板中有自定义字段
        if (!CollectionUtils.isEmpty(idTemplateList)) {
            // 字段名-字段 Map
            Map<String, CompanyAdditionalFieldsListVO> fieldNameCompanyAdditionalFieldsListVOMap = nullTemplateList.stream()
                    .collect(Collectors.toMap(CompanyAdditionalFieldsListVO::getFieldName, v -> v, (v1, v2) -> v1));
            Iterator<CompanyAdditionalFieldsListVO> iterator = idTemplateList.iterator();
            while (iterator.hasNext()) {
                CompanyAdditionalFieldsListVO next = iterator.next();
                String fieldName = next.getFieldName();
                CompanyAdditionalFieldsListVO fieldsListVO = fieldNameCompanyAdditionalFieldsListVOMap.get(fieldName);
                if (fieldsListVO != null && Boolean.TRUE.equals(fieldsListVO.getIsOpen())) {
                    next.setId(fieldsListVO.getId());
                } else {
                    // 在noTemplateIdList中没有对应字段，删除
                    iterator.remove();
                }
            }
        }
        customTemplateVO.setAdditionalFieldsListVOS(idTemplateList);

        return customTemplateVO;
    }

    @Override
    public CustomTemplateVO selectOpenTemplate2(String moduleCode, String companyId, TokenUser tokenUser) {
        // 查询租户
        if (CustomerModuleType.CHECK_IN.getValue().equals(moduleCode)) {
            if (!HrConstants.ADD_FIELD_COMPANY_SITE.equals(companyId)) {
                throw new ParamException("预登记模板只有租户使用");
            }
        }

        List<CustomTemplateDO> customTemplateDOS = selectOpen(companyId, moduleCode, tokenUser);
        CustomTemplateVO customTemplateVO;
        // 如果没有开启的，就返回系统默认模板
        if (CollectionUtils.isEmpty(customTemplateDOS)) {
            List<CustomTemplateDO> customTemplateDOS1 = selectBySystem(null, moduleCode);
            customTemplateVO = customTemplateDOS1.get(0).to(CustomTemplateVO.class);
        } else {
            customTemplateVO = customTemplateDOS.get(0).to(CustomTemplateVO.class);
        }
        // 开启的模板id
        String openTemplateId = customTemplateVO.getId();

        // 系统字段
        List<CustomTemplateFieldVO> customTemplateFieldVOList = customTemplateFieldService.listByTemplateId(openTemplateId, tokenUser);
        customTemplateFieldVOList = customTemplateFieldVOList.parallelStream().filter(customTemplateFieldVO -> companyNecessaryFieldService
                .filterField(customTemplateFieldVO.getFieldName(), tokenUser.getSiteId())).parallel().collect(Collectors.toList());

        customTemplateVO.setCustomTemplateFieldVOList(customTemplateFieldVOList);
        // 模板自定义字段
        List<CompanyAdditionalFieldsListVO> idTemplateList = companyAdditionalFieldsService.listByCompanyId(null,
                companyId, openTemplateId, tokenUser);
        List<CompanyAdditionalFieldsListVO> nullTemplateList;
        // 预登记模板使用租户级预登记的自定义字段Id 入职/待入职使用花名册自定义Id(预登记的值存在租户中 入职/待入职的值存在用工单位花名册中)
        if ("checkIn".equals(moduleCode)) {
            // 租户级预登记的自定义字段
            nullTemplateList = companyAdditionalFieldsService
                    .listByCompanyId("checkIn", "site", HrConstants.TEMPLATE_ID_LIST, tokenUser);
        } else {
            // 花名册自定义字段
            nullTemplateList = companyAdditionalFieldsService
                    .selectByCompanyId2(companyId, null, tokenUser.getSiteId());
        }
        // 如果开启的模板中有自定义字段
        if (!CollectionUtils.isEmpty(idTemplateList)) {
            // 字段名-字段 Map
            Map<String, CompanyAdditionalFieldsListVO> fieldNameCompanyAdditionalFieldsListVOMap = nullTemplateList.stream()
                    .collect(Collectors.toMap(CompanyAdditionalFieldsListVO::getFieldName, v -> v, (v1, v2) -> v1));
            Iterator<CompanyAdditionalFieldsListVO> iterator = idTemplateList.iterator();
            while (iterator.hasNext()) {
                CompanyAdditionalFieldsListVO next = iterator.next();
                String fieldName = next.getFieldName();
                CompanyAdditionalFieldsListVO companyAdditionalFieldsListVO = fieldNameCompanyAdditionalFieldsListVOMap.get(fieldName);
                if (companyAdditionalFieldsListVO != null) {
                    next.setId(companyAdditionalFieldsListVO.getId());
                } else {
                    // 在noTemplateIdList中没有对应字段，删除
                    iterator.remove();
                }
            }
        }
        customTemplateVO.setAdditionalFieldsListVOS(idTemplateList);

        return customTemplateVO;
    }

    @Override
    public CustomTemplateVO selectOpenTemplate3(String moduleCode, String companyId, TokenUser tokenUser) {
        // BugId：ID1003510 批量确认到岗表单写死
        ParamException.isTrue(CustomerModuleType.ON_JOB.getValue().equals(moduleCode), "模板类型有误");
        List<CustomTemplateDO> customTemplateDOS = selectOpen(companyId, moduleCode, tokenUser);
        CustomTemplateVO customTemplateVO;
        // 如果没有开启的，就返回系统默认模板
        if (CollectionUtils.isEmpty(customTemplateDOS)) {
            List<CustomTemplateDO> customTemplateDOS1 = selectBySystem(null, moduleCode);
            customTemplateVO = customTemplateDOS1.get(0).to(CustomTemplateVO.class);
        } else {
            customTemplateVO = customTemplateDOS.get(0).to(CustomTemplateVO.class);
        }
        // 开启的模板id
        String openTemplateId = customTemplateVO.getId();

        // 系统字段
        List<CustomTemplateFieldVO> customTemplateFieldVOList = customTemplateFieldService.listByTemplateId(openTemplateId, tokenUser);
        ArrayList<String> hadList = new ArrayList<>(Arrays.asList("姓名", "入职日期", "备注"));
        customTemplateFieldVOList = customTemplateFieldVOList.parallelStream().map(customTemplateFieldVO -> {
            if (hadList.contains(customTemplateFieldVO.getFieldName())) {
                customTemplateFieldVO.setIsOpen(Boolean.TRUE);
                return customTemplateFieldVO;
            } else {
                return null;
            }
        }).filter(Objects::nonNull).collect(Collectors.toList());
        customTemplateVO.setCustomTemplateFieldVOList(customTemplateFieldVOList);
        customTemplateVO.setAdditionalFieldsListVOS(new ArrayList<>());
        return customTemplateVO;
    }

    @Override
    public CustomFieldValueVO getCheckInField(String checkInId, TokenUser tokenUser) {
        // 预登记人员
        CheckInPeopleVO checkInPeopleVO = checkInPeopleService.selectById(checkInId, tokenUser.getSiteId());
        CustomFieldValueVO customFieldValueVO = setFieldData(checkInId, checkInPeopleVO, CustomerModuleType.CHECK_IN.getValue(),
                HrConstants.ADD_FIELD_COMPANY_SITE, tokenUser);
        customFieldValueVO.setCheckInPeopleVO(checkInPeopleVO);
        return customFieldValueVO;
    }

    @Override
    public CustomFieldValueVO getEmpField(String empId, String moduleType, TokenUser tokenUser) {
        if (!CustomerModuleType.ON_JOB.getValue().equals(moduleType)
                && !CustomerModuleType.WAIT_JOB.getValue().equals(moduleType)) {
            throw new ParamException("moduleType非法");
        }
        // 员工信息
        EmpInfoVO empInfoVO = empInfoService.selectById(empId, tokenUser.getSiteId());
        ParamException.notNull(empInfoVO, "员工信息不存在");

        // 家庭成员，取创建时间最早的一条
        List<EmpFamilyDO> empFamilyList = familyService.listByEmpId(empId, tokenUser.getSiteId());
        if (!CollectionUtils.isEmpty(empFamilyList)) {
            // 创建时间正序
            empFamilyList = empFamilyList.stream().sorted(Comparator.comparing(EmpFamilyDO::getGmtModified)).collect(Collectors.toList());
            EmpFamilyDO empFamilyDO = empFamilyList.get(0);
            empInfoVO.setFamilyName(empFamilyDO.getName());
            empInfoVO.setFamilyPhone(empFamilyDO.getPhone());
            empInfoVO.setFamilyRelation(empFamilyDO.getRelation());
            empInfoVO.setFamilyWorkUnit(empFamilyDO.getWorkUnit());
        }
        // 紧急联系人，取创建时间最早的一条
        List<EmpContactsDO> empContactList = contactsService.listByEmpId(empId, tokenUser.getSiteId());
        if (!CollectionUtils.isEmpty(empContactList)) {
            empContactList = empContactList.stream().sorted(Comparator.comparing(EmpContactsDO::getGmtModified)).collect(Collectors.toList());
            EmpContactsDO empContactsDO = empContactList.get(0);
            empInfoVO.setContactsName(empContactsDO.getName());
            empInfoVO.setContactsPhone(empContactsDO.getPhone());
            empInfoVO.setContactsRelation(empContactsDO.getRelation());
            empInfoVO.setContactsAddress(empContactsDO.getAddress());
        }
        // 教育经历
        List<EmpEducationDO> empEducationDOList = empEducationService.listByEmpId(empId, tokenUser.getSiteId());
        if (!CollectionUtils.isEmpty(empEducationDOList)) {
            empEducationDOList = empEducationDOList.stream().sorted(Comparator.comparing(EmpEducationDO::getGmtCreate))
                    .collect(Collectors.toList());
            EmpEducationDO empEducationDO = empEducationDOList.get(0);
            empInfoVO.setEducation(empEducationDO.getEducation());
            empInfoVO.setGraCollege(empEducationDO.getGraCollege());
            empInfoVO.setMajor(empEducationDO.getMajor());
            empInfoVO.setStartTime(empEducationDO.getStartTime());
            empInfoVO.setEndTime(empEducationDO.getEndTime());
            empInfoVO.setEduStartTime(empEducationDO.getStartTime());
            empInfoVO.setEduEndTime(empEducationDO.getEndTime());
            empInfoVO.setTeaMethods(empEducationDO.getTeaMethods());
            empInfoVO.setGraCerNumber(empEducationDO.getGraCerNumber());
            empInfoVO.setDegreeType(empEducationDO.getDegreeType());
            empInfoVO.setDegreeName(empEducationDO.getDegreeName());
            empInfoVO.setDegreeNumber(empEducationDO.getDegreeNumber());
            empInfoVO.setEducationRemark(empEducationDO.getEducationRemark());
        }
        // 工作经历
        List<EmpWorkDO> empWorkDOList = empWorkService.listByEmpId(empId, tokenUser.getSiteId());
        if (!CollectionUtils.isEmpty(empWorkDOList)) {
            empWorkDOList = empWorkDOList.stream().sorted(Comparator.comparing(EmpWorkDO::getGmtCreate))
                    .collect(Collectors.toList());
            EmpWorkDO empWorkDO = empWorkDOList.get(0);
            empInfoVO.setCompany(empWorkDO.getCompany());
            empInfoVO.setPosition(empWorkDO.getPosition());
            empInfoVO.setWorkStartTime(empWorkDO.getStartTime());
            empInfoVO.setWorkEndTime(empWorkDO.getEndTime());
            empInfoVO.setWitName(empWorkDO.getWitName());
            empInfoVO.setWitPhone(empWorkDO.getWitPhone());
            empInfoVO.setLeaveReason(empWorkDO.getLeaveReason());
            empInfoVO.setLeaveSalary(empWorkDO.getLeaveSalary());
            empInfoVO.setWorkRemark(empWorkDO.getRemark());
        }
        // 培训经历
        List<EmpTrainDO> empTrainDOList = empTrainService.listByEmpId(empId, tokenUser.getSiteId());
        if (!CollectionUtils.isEmpty(empTrainDOList)) {
            empTrainDOList = empTrainDOList.stream().sorted(Comparator.comparing(EmpTrainDO::getGmtCreate))
                    .collect(Collectors.toList());
            EmpTrainDO empTrainDO = empTrainDOList.get(0);
            empInfoVO.setTrainCourse(empTrainDO.getTrainCourse());
            empInfoVO.setTrainOrgName(empTrainDO.getTrainOrgName());
            empInfoVO.setTrainStartTime(empTrainDO.getStartTime());
            empInfoVO.setTrainEndTime(empTrainDO.getEndTime());
            empInfoVO.setAssessResult(empTrainDO.getAssessResult());
            empInfoVO.setTrainCerName(empTrainDO.getTrainCerName());
            empInfoVO.setTrainCerNumber(empTrainDO.getTrainCerNumber());
            empInfoVO.setRemake(empTrainDO.getRemake());
        }
        // 奖惩记录
        List<EmpRewardPunishDO> empRewardPunishDOList =
                empRewardPunishService.listByEmpId(empId, tokenUser.getSiteId());
        if (!CollectionUtils.isEmpty(empRewardPunishDOList)) {
            empRewardPunishDOList = empRewardPunishDOList.stream()
                    .sorted(Comparator.comparing(EmpRewardPunishDO::getGmtCreate)).collect(Collectors.toList());
            EmpRewardPunishDO empRewardPunishDO = empRewardPunishDOList.get(0);
            empInfoVO.setRewardPunish(empRewardPunishDO.getRewardPunish());
            empInfoVO.setRewardType(empRewardPunishDO.getRewardType());
            empInfoVO.setPunishType(empRewardPunishDO.getPunishType());
            empInfoVO.setHandleDate(empRewardPunishDO.getHandleDate());
            empInfoVO.setContent(empRewardPunishDO.getContent());
            empInfoVO.setAmount(empRewardPunishDO.getAmount());
            empInfoVO.setReason(empRewardPunishDO.getReason());
            empInfoVO.setRewardsRemark(empRewardPunishDO.getRemark());
        }
        CustomFieldValueVO customFieldValueVO = setFieldData(empId, empInfoVO, moduleType, empInfoVO.getCompanyId(), tokenUser);
        customFieldValueVO.setEmpInfoVO(empInfoVO);
        return customFieldValueVO;
    }

    /**
     * @param businessId 业务id
     * @param object     数据对象
     * @param moduleType 模块类型
     * @param companyId  用工单位id
     * @param tokenUser  当前用户
     */
    private CustomFieldValueVO setFieldData(String businessId, Object object, String moduleType, String companyId, TokenUser tokenUser) {
        // 预登记开启的自定义模板
        CustomTemplateVO customTemplateVO = selectOpenTemplate2(moduleType, companyId, tokenUser);
        // 系统字段
        List<CustomTemplateFieldVO> customTemplateFieldVOList = customTemplateVO.getCustomTemplateFieldVOList();
        List<CheckInEmpAdditionalFieldVO> additionalFieldVOList = new ArrayList<>();
        // 自定义字段
        List<CompanyAdditionalFieldsListVO> additionalFieldsListVOS = customTemplateVO.getAdditionalFieldsListVOS();
        if (!CollectionUtils.isEmpty(additionalFieldsListVOS)) {
            for (CompanyAdditionalFieldsListVO additionalFieldsListVO : additionalFieldsListVOS) {
                EmpAdditionalFieldsDO empAdditionalFieldsDO
                        = empAdditionalFieldsService.selectByFiledIdAndEmpId(additionalFieldsListVO.getId(), businessId);
                CheckInEmpAdditionalFieldVO empAdditionalFieldVO = new CheckInEmpAdditionalFieldVO();
                if (empAdditionalFieldsDO == null) {
                    CompanyAdditionalFieldsVO fieldsVO = companyAdditionalFieldsService.selectById(additionalFieldsListVO.getId(), tokenUser.getSiteId());
                    if (fieldsVO != null) {
                        empAdditionalFieldVO.setFieldName(fieldsVO.getFieldName());
                        empAdditionalFieldVO.setFieldId(fieldsVO.getId());
                        empAdditionalFieldVO.setFieldType(fieldsVO.getFieldType());
                        additionalFieldVOList.add(empAdditionalFieldVO);
                    }
                } else {
                    empAdditionalFieldVO.setFieldName(additionalFieldsListVO.getFieldName());
                    empAdditionalFieldVO.setFieldId(empAdditionalFieldsDO.getFieldId());
                    empAdditionalFieldVO.setFieldType(additionalFieldsListVO.getFieldType());
                    empAdditionalFieldVO.setEmpAdditionalId(empAdditionalFieldsDO.getId());
                    empAdditionalFieldVO.setContent(empAdditionalFieldsDO.getContent());
                    additionalFieldVOList.add(empAdditionalFieldVO);
                }
            }
        }
        CustomFieldValueVO customFieldValueVO = new CustomFieldValueVO();
        customFieldValueVO.setAdditionalFieldVOList(additionalFieldVOList);

        //其他字段的值全从员工表中取
        Map<String, String> dataMap = processCustomFieldList(customTemplateFieldVOList, object, moduleType);
        customFieldValueVO.setData(dataMap);
        return customFieldValueVO;
    }

    /**
     * 将预登记/员工信息的值注入到字段列表的属性中
     *
     * @param fieldList  字段列表
     * @param object     预登记对象/员工信息对象
     * @param moduleType 模块类型
     */
    private static Map<String, String> processCustomFieldList(List<CustomTemplateFieldVO> fieldList, Object object, String moduleType) {
        String title;
        if (CustomerModuleType.CHECK_IN.getValue().equals(moduleType)) {
            title = "预登记人员表";
        } else {
            title = "员工表";
        }
        Map<String, String> dataMap = new HashMap<>(16);
        if (object == null) {
            return dataMap;
        }
        for (CustomTemplateFieldVO customTemplateFieldVO : fieldList) {
            String fieldCode = customTemplateFieldVO.getFieldCode();
            try {
                Object value = ClassKit.getValue(object, fieldCode);
                dataMap.put(customTemplateFieldVO.getFieldCode(), SafeKit.getString(value));
            } catch (Exception e) {
                log.error(title + "未找到" + fieldCode + "字段!");
            }
        }
        return dataMap;
    }


    /**
     * 新建时校验模板
     */
    void checkTemplateForAdd(CustomTemplateAddDTO customTemplateAddDTO, TokenUser tokenUser) {
        String name = customTemplateAddDTO.getName();
        String companyId = customTemplateAddDTO.getCompanyId();
        String moduleCode = customTemplateAddDTO.getModuleCode();
        Integer type = customTemplateAddDTO.getType();
        ParamException.hasText(moduleCode, "moduleCode不能为空");
        if (StrKit.isNotEmpty(customTemplateAddDTO.getModuleName())) {
            customTemplateAddDTO.setModuleName(CustomerModuleType.find(moduleCode).getDesc());
        }
        List<CustomTemplateFieldAddDTO> fieldAddDTOList = customTemplateAddDTO.getCustomFieldAddDTOList();
        ParamException.notEmpty(fieldAddDTOList, "模板字段不能为空");
        ParamException.notNull(type, "type不能为空");
        customTemplateAddDTO.setEditBy(tokenUser.getUserName());

        if (Boolean.TRUE.equals(customTemplateAddDTO.getIsDefault())) {
            if (!DEFAULT_TEMPLATE_NAME.equals(name)) {
                throw new ParamException("默认模板不允许修改模板名称");
            }
        } else {
            // 校验模板重名
            ParamException.hasText(name, "模板名称不能为空");
            boolean hasSameName = hasSameName(name, moduleCode, companyId, type, tokenUser);
            if (hasSameName) {
                throw new ParamException("已存在同名模板");
            }
        }
    }


    /**
     * 编辑时校验模板
     */
    void checkTemplateForUpdate(CustomTemplateUpdateDTO customTemplateUpdateDTO, TokenUser tokenUser) {
        String name = customTemplateUpdateDTO.getName();
        String companyId = customTemplateUpdateDTO.getCompanyId();
        String moduleCode = customTemplateUpdateDTO.getModuleCode();
        Integer type = customTemplateUpdateDTO.getType();
        ParamException.hasText(moduleCode, "moduleCode不能为空");
        customTemplateUpdateDTO.setModuleName(CustomerModuleType.find(moduleCode).getValue());
        List<CustomTemplateFieldAddDTO> fieldAddDTOList = customTemplateUpdateDTO.getCustomFieldAddDTOList();
        ParamException.notEmpty(fieldAddDTOList, "模板字段不能为空");
        ParamException.notNull(type, "type不能为空");
        customTemplateUpdateDTO.setEditBy(tokenUser.getUserName());
        if (Boolean.TRUE.equals(customTemplateUpdateDTO.getIsDefault())) {
            if (!DEFAULT_TEMPLATE_NAME.equals(name)) {
                throw new ParamException("默认模板不允许修改模板名称");
            }
        } else {
            // 校验模板重名
            ParamException.hasText(name, "模板名称不能为空");
            List<CustomTemplateVO> customTemplateVOList = selectSameNameTemplate(name, moduleCode, companyId, type, false, tokenUser);
            if (!CollectionUtils.isEmpty(customTemplateVOList)) {
                for (CustomTemplateVO customTemplateVO : customTemplateVOList) {
                    // 同名的不是不是当前模板
                    if (!customTemplateVO.getId().equals(customTemplateUpdateDTO.getId())) {
                        throw new ParamException("已存在同名模板");
                    }
                }
            }
        }
    }

    /**
     * 查询开启的模板
     */
    private List<CustomTemplateDO> selectOpen(List<CustomTemplateDO> customTemplateDOS) {
        List<CustomTemplateDO> list = new ArrayList<>();
        for (CustomTemplateDO customTemplateDO : customTemplateDOS) {
            if (Boolean.TRUE.equals(customTemplateDO.getIsOpen())) {
                list.add(customTemplateDO);
            }
        }
        return list;
    }


    /**
     * 根据查询参数，构建example
     *
     * @param customTemplateQuery 查询参数
     * @param siteId              所属站点id
     * @return example
     */
    private Example buildExample(CustomTemplateQuery customTemplateQuery, String siteId) {
        Example example = new Example(CustomTemplateDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        if (customTemplateQuery.getModuleCode() != null) {
            example.and().andEqualTo("moduleCode", customTemplateQuery.getModuleCode());
        }
        if (customTemplateQuery.getName() != null) {
            example.and().andLike("name", "%" + customTemplateQuery.getName() + "%");
        }
        // 排序
        ExampleKit.setExampleOrder(example, customTemplateQuery.getOrders());
        return example;
    }
}




